// SPDX-License-Identifier: GPL-2.0
/*
 * ir_csp.c - CSP API of LomboTech IR module
 *
 * Copyright (C) 2016-2018, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "ir_csp.h"

/*
 * csp_ir_set_en - set IR enable
 * @en: 1, enable; 0, disable
 *
 */
void csp_ir_set_en(void *base, bool en)
{
	reg_ir_ctl_t reg;

	reg.val = READREG32(base + IR_CTL_OFF);
	reg.bits.ir_en = en ? 1 : 0;

	WRITEREG32(base + IR_CTL_OFF, reg.val);
}

/*
 * csp_ir_set_int_en - set IR interrupt enable
 * @t: select bit
 * @en: 1, interrupt enable; 0, interrupt disable
 *
 */
void csp_ir_set_int_en(void *base, int t, bool en)
{
	reg_ir_int_en_t reg;

	reg.val = READREG32(base + IR_INT_EN_OFF);
	switch (t) {
	case K_IR_F_ERR:
		/* IR frame error interrupt enable */
		reg.bits.ir_f_err = en ? 1 : 0;
		break;
	case K_IR_REPEAT:
		/* IR repeat interrupt enable */
		reg.bits.ir_repeat = en ? 1 : 0;
		break;
	case K_IR_FRAME:
		/* IR frame interrupt enable */
		reg.bits.ir_frame = en ? 1 : 0;
		break;
	case K_IR_START:
		/* IR start interrupt enable */
		reg.bits.ir_start = en ? 1 : 0;
		break;
	default:
		pr_err("Unknown interrupt type: %d\n", t);
	}

	WRITEREG32(base + IR_INT_EN_OFF, reg.val);
}

/*
 * csp_ir_int_clr - clear IR interrupt pending
 * @t: select bit
 *
 * the bit of interrupt is writing 1 clears pending
 */
void csp_ir_int_clr(void *base, int t)
{
	reg_ir_int_clr_t reg;

	switch (t) {
	case K_IR_F_ERR:
		reg.bits.ir_f_err = 1;
		break;
	case K_IR_REPEAT:
		reg.bits.ir_repeat = 1;
		break;
	case K_IR_FRAME:
		reg.bits.ir_frame = 1;
		break;
	case K_IR_START:
		reg.bits.ir_start = 1;
		break;
	default:
		pr_err("Unknown clear int type: %d\n", t);
	}

	WRITEREG32(base + IR_INT_CLR_OFF, reg.val);
}

/*
 * csp_ir_ld_int_enable - set IR interrupt enable
 * @t: 0, NEC; 1, SIRC; 2, RC5; 3, RC6
 * @en: 1, interrupt enable; 0, interrupt disable
 *
 */
void csp_ir_set_protocol(void *base, int p)
{
	reg_ir_ctl_t reg;

	reg.val = READREG32(base + IR_CTL_OFF);
	switch (p) {
	case K_IR_PROTOCOL_NEC:
		reg.bits.protocol_sel = 0;
		break;
	case K_IR_PROTOCOL_SONY_SIRC:
		reg.bits.protocol_sel = 1;
		break;
	case K_IR_PROTOCOL_RC5:
		reg.bits.protocol_sel = 2;
		break;
	case K_IR_PROTOCOL_RC6:
		reg.bits.protocol_sel = 3;
		break;
	default:
		pr_err("Unknown protocol type: %d\n", p);
	}

	WRITEREG32(base + IR_CTL_OFF, reg.val);
}

/*
 * csp_ir_set_sirc_ext - SIRC protocol select
 * @ext: 0, 12bit frame; 1, 15bit frame; 2, 20bit frame; 3, auto-adjust frame
 *
 */
void csp_ir_set_sirc_ext(void *base, u32 ext)
{
	reg_ir_ctl_t reg;

	reg.val = READREG32(base + IR_CTL_OFF);
	reg.bits.sirc_ext = ext;

	WRITEREG32(base + IR_CTL_OFF, reg.val);
}

/*
 * csp_ir_set_clk_div - set IR clock diver
 * @div: frequency division
 *
 */
void csp_ir_set_clk_div(void *base, u32 div)
{
	reg_ir_ctl_t reg;

	/* ir_clk=cir_clk/(clk_div+1) */
	reg.val = READREG32(base + IR_CTL_OFF);
	reg.bits.clk_div = div - 1;

	WRITEREG32(base + IR_CTL_OFF, reg.val);
}

/*
 * csp_ir_set_timeout_th - set IR timeout threshold
 * @th: timeout threshold
 *
 */
void csp_ir_set_timeout_th(void *base, u32 th)
{
	reg_ir_timeout_th_t reg;

	reg.val = READREG32(base + IR_TIMEOUT_TH_OFF);
	reg.bits.thd = th;

	WRITEREG32(base + IR_TIMEOUT_TH_OFF, reg.val);
}

/*
 * csp_ir_set_noise_th - set IR noise threshold
 * @th: timeout threshold
 *
 */
void csp_ir_set_noise_th(void *base, u32 th)
{
	reg_ir_noise_th_t reg;

	reg.val = READREG32(base + IR_NOISE_TH_OFF);
	reg.bits.thd = th;

	WRITEREG32(base + IR_NOISE_TH_OFF, reg.val);
}

/*
 * csp_ir_get_data - get IR received data
 * @param: none
 *
 * return: IR frame
 *
 */
u32 csp_ir_get_data(void *base)
{
	reg_ir_data_t reg;

	/* this value store the received byte of the IR frame */
	reg.val = READREG32(base + IR_DATA_OFF);
	return reg.bits.data;
}

#ifndef CONFIG_ARCH_LOMBO_N7V1
/*
 * csp_ir_set_short_adj - set IR short adjustment
 * @adj: adjustment
 *
 */
void csp_ir_set_short_adj(void *base, u32 adj)
{
	reg_ir_sadj_t reg;

	reg.val = READREG32(base + IR_SADJ_OFF);
	reg.bits.sadj = adj;

	WRITEREG32(base + IR_SADJ_OFF, reg.val);
}

/*
 * csp_ir_set_long_adj - set IR long adjustment
 * @adj: adjustment
 *
 */
void csp_ir_set_long_adj(void *base, u32 adj)
{
	reg_ir_ladj_t reg;

	reg.val = READREG32(base + IR_LADJ_OFF);
	reg.bits.ladj = adj;

	WRITEREG32(base + IR_LADJ_OFF, reg.val);
}
#endif

#ifdef CONFIG_ARCH_LOMBO_N9V3

/* set power key wake up function enable */
void csp_ir_set_wk_en(void *base, u32 en)
{
	reg_ir_t *reg_base = base;
	reg_ir_ctl_t reg;

	reg.val = READREG32(&(reg_base->ctl));
	reg.bits.wk_en = en;

	WRITEREG32(&(reg_base->ctl), reg.val);
}

/* if set that, it will reset all registers and state machine */
void csp_ir_set_ir_rstn(void *base, u32 reset)
{
	reg_ir_t *reg_base = base;
	reg_ir_ctl_t reg;

	reg.val = READREG32(&(reg_base->ctl));
	reg.bits.ir_rstn = reset;

	WRITEREG32(&(reg_base->ctl), reg.val);
}

/* set ir module clock source */
void csp_ir_set_clk_src(void *base, enum ir_clk_src src)
{
	reg_ir_t *reg_base = base;
	reg_ir_ctl_t reg;

	reg.val = READREG32(&(reg_base->ctl));
	reg.bits.clk_src = src;

	WRITEREG32(&(reg_base->ctl), reg.val);
}

void csp_ir_set_wake_expect_data(void *base, u32 exp_data)
{
	reg_ir_t *reg_base = base;
	reg_ir_exp_data_t reg;

	reg.val = READREG32(&(reg_base->exp_data));
	reg.bits.edata = exp_data;

	WRITEREG32(&(reg_base->exp_data), reg.val);
}

u32 csp_ir_get_wake_expect_data(void *base)
{
	reg_ir_t *reg_base = base;
	reg_ir_exp_data_t reg;

	reg.val = READREG32(&(reg_base->exp_data));

	return reg.bits.edata;
}

void csp_ir_set_wake_data_mask(void *base, u32 wk_mask)
{
	reg_ir_t *reg_base = base;
	reg_ir_wk_mask_t reg;

	reg.val = READREG32(&(reg_base->wk_mask));
	reg.bits.mask = wk_mask;

	WRITEREG32(&(reg_base->wk_mask), reg.val);
}

u32 csp_ir_get_wake_data_mask(void *base)
{
	reg_ir_t *reg_base = base;
	reg_ir_wk_mask_t reg;

	reg.val = READREG32(&(reg_base->wk_mask));

	return reg.bits.mask;
}

#endif
